#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ZestyParser import *

cmmt     = Omit(Omit(RE('\s;.*')) | EmptyToken)
ws       = Omit(RE('\s+'))

#state    = Token('[0-9]+')
state    = Token('#[a-zA-Z0-9\_]+')
marker   = Token('[0-5]')

sensedir = Token('Here') | Token('Ahead') | Token('LeftAhead') | Token('RightAhead')
cond     = Token('Friend') | Token('Foe') | Token('FriendsWithFood') | Token('FoeWithFood') | Token('Food') | Token('Rock') | (Token('Marker')+ws+marker) | Token('FoeMarker') | Token('Home') | Token('FoeHome')
side     = Token('Left') | Token('Right')


def combine(*arr):
    return reduce(lambda x,y: x+ws+y, arr[1:], arr[0]) + cmmt

label  = combine(state)
sense  = combine(Token('Sense'),  sensedir, state, state, cond)
mark   = combine(Token('Mark'),   marker, state)
unmark = combine(Token('Unmark'), marker, state)
pickup = combine(Token('PickUp'), state, state)
drop   = combine(Token('Drop'),   state)
turn   = combine(Token('Turn'),   side, state)
move   = combine(Token('Move'),   state, state)
flip   = combine(Token('Flip'),   Token('[0-9]+'), state, state)

state =  sense | mark | unmark | pickup | drop | turn | move | flip | label

def parse(lines):
    result = []
    for line in lines:
        res = ZestyParser(line).scan(state)
        if res is None:
            raise Exception("Invalid line '%s'"%line)
        result.append([x for x in res])
    return result

class State(object) : 
    def __init__(self, label, num = -1):
        self.label = label
        self.num   = num


class Assemble:
    def __init__(self):
        self.table      = {}
        self.state_cns  = 0
        self.curr_state = None
        self.next_state = None

    def _create_state(self, name=None):
        if not name:
            self.state_cns += 1
            name = "#state-%s"%self.state_cns
        st = State(name)
        self.table[name] = st
        return st

    def create_state(self, name=None):
        print 'create for', name
        if name == '#next':
            if self.next_state:
                return self.next_state
            else:
                self.next_state = self._create_state()
                return self.next_state

        if name and self.table.has_key(name):
            print 'cached', name
            return self.table[name]

        return self._create_state(name)
    
    def process_line(self, line):
        if not self.curr_state:            
            self.curr_state = self.create_state()
            print self.curr_state.label

        item   = line[0].group()
        result = None
        # Метка
        if item.startswith('#'):
            print self.curr_state.label, '->', item
            self.curr_state.label = item             
            self.table[item] = self.curr_state            
            return None
        elif item == 'Sense':
            result = (self.curr_state,[line[0], line[1], self.create_state(line[2].group()), self.create_state(line[3].group()), line[4]])
        elif item == 'Mark':
            result = (self.curr_state,[line[0], line[1], self.create_state(line[2].group())])
        elif item == 'Unmark':
            result = (self.curr_state,[line[0], line[1], self.create_state(line[2].group())])
        elif item == 'PickUp':
            result = (self.curr_state,[line[0], self.create_state(line[1].group()), self.create_state(line[2].group())])
        elif item == 'Drop':
            result = (self.curr_state,[line[0], self.create_state(line[1].group())])
        elif item == 'Turn':
            result = (self.curr_state,[line[0], line[1], self.create_state(line[2].group())])
        elif item == 'Move':
            result = (self.curr_state,[line[0], self.create_state(line[1].group()), self.create_state(line[2].group())])
        elif item == 'Flip':
            result = (self.curr_state,[line[0], line[1], self.create_state(line[2].group()), self.create_state(line[3].group())])
            
        self.curr_state = self.next_state
        self.next_state = None

        return result

    def load_ast(self, ast):
        result = []
        for line in ast:
            elem = self.process_line(line)
            if elem:
                result.append(elem)
        return result

    def output(self, loaded):
        cnt = 0;
        for state, item in loaded:
            state.num = cnt
            print state.label,'=>',state.num
            cnt += 1
        
        result = []
        for state, item in loaded:
            step = []
            for elem in item:
                if type(elem) == State:
                    if elem.num == -1:
                        elem = self.table[elem.label]
                    step.append(str(elem.num))
                else:
                    step.append(elem.group())
            result.append(' '.join(step)+'\n')
        return result


if __name__ == '__main__':
    import sys
    if len(sys.argv) < 3:
        print 'usage ast_parse input output'
    else:
        f = file(sys.argv[1])
        parsed = parse(f.readlines())
        a = Assemble()
        ast = a.load_ast(parsed)
        output = a.output(ast)
        o = file(sys.argv[2],'w')
        o.writelines(output)
        f.close()
        o.close()
